{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a name=\"top\"></a><img src=\"./source/SpinalHDL.png\" alt=\"SpinalHDL based on Scala\" style=\"width:320px;\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Before running Spinal HDL code, be sure to load SpinalHDL Libraries  \n",
    "**Note** : This may be a little slow when the first time load, please wait a moment to download Lib from remote.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val path = System.getProperty(\"user.dir\") + \"/source/load-spinal.sc\"\n",
    "interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [APB3 definition](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Examples/Simple%20ones/apb3.html)\n",
    "#### Implementation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "case class Apb3Config(\n",
    "  addressWidth  : Int,\n",
    "  dataWidth     : Int,\n",
    "  selWidth      : Int     = 1,\n",
    "  useSlaveError : Boolean = true\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "case class Apb3(config: Apb3Config) extends Bundle with IMasterSlave {\n",
    "  val PADDR      = UInt(config.addressWidth bit)\n",
    "  val PSEL       = Bits(config.selWidth bits)\n",
    "  val PENABLE    = Bool\n",
    "  val PREADY     = Bool\n",
    "  val PWRITE     = Bool\n",
    "  val PWDATA     = Bits(config.dataWidth bit)\n",
    "  val PRDATA     = Bits(config.dataWidth bit)\n",
    "  val PSLVERROR  = if(config.useSlaveError) Bool else null\n",
    "\n",
    "  override def asMaster(): Unit = {\n",
    "    out(PADDR,PSEL,PENABLE,PWRITE,PWDATA)\n",
    "    in(PREADY,PRDATA)\n",
    "    if(config.useSlaveError) in(PSLVERROR)\n",
    "  }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Usage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val apbConfig = Apb3Config(\n",
    "  addressWidth  = 16,\n",
    "  dataWidth     = 32,\n",
    "  selWidth      = 1,\n",
    "  useSlaveError = false\n",
    ")\n",
    "\n",
    "val io = new Bundle{\n",
    "  val apb = slave(Apb3(apbConfig))\n",
    "}\n",
    "\n",
    "io.apb.PREADY := True\n",
    "when(io.apb.PSEL(0) && io.apb.PENABLE){\n",
    "  //...\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Carry adder](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Examples/Simple%20ones/carry_adder.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CarryAdder(size : Int) extends Component{\n",
    "  val io = new Bundle{\n",
    "    val a = in UInt(size bits)\n",
    "    val b = in UInt(size bits)\n",
    "    val result = out UInt(size bits)      //result = a + b\n",
    "  }\n",
    "\n",
    "  var c = False                   //Carry, like a VHDL variable\n",
    "  for (i <- 0 until size) {\n",
    "    //Create some intermediate value in the loop scope.\n",
    "    val a = io.a(i)\n",
    "    val b = io.b(i)\n",
    "\n",
    "    //The carry adder's asynchronous logic\n",
    "    io.result(i) := a ^ b ^ c\n",
    "    c \\= (a & b) | (a & c) | (b & c);    //variable assignment\n",
    "  }\n",
    "}\n",
    "\n",
    "showRtl(new CarryAdder(4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Color summing](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Examples/Simple%20ones/color_summing.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "case class Color(channelWidth: Int) extends Bundle {\n",
    "  val r = UInt(channelWidth bits)\n",
    "  val g = UInt(channelWidth bits)\n",
    "  val b = UInt(channelWidth bits)\n",
    "\n",
    "  def +(that: Color): Color = {\n",
    "    val result = Color(channelWidth)\n",
    "    result.r := this.r + that.r\n",
    "    result.g := this.g + that.g\n",
    "    result.b := this.b + that.b\n",
    "    return result\n",
    "  }\n",
    "\n",
    "  def clear(): Color ={\n",
    "    this.r := 0\n",
    "    this.g := 0\n",
    "    this.b := 0\n",
    "    this\n",
    "  }\n",
    "}\n",
    "\n",
    "class ColorSumming(sourceCount: Int, channelWidth: Int) extends Component {\n",
    "  val io = new Bundle {\n",
    "    val sources = in Vec(Color(channelWidth), sourceCount)\n",
    "    val result = out(Color(channelWidth))\n",
    "  }\n",
    "\n",
    "  var sum = Color(channelWidth)\n",
    "  sum.clear()\n",
    "  for (i <- 0 to sourceCount - 1) {\n",
    "    sum \\= sum + io.sources(i)\n",
    "  }\n",
    "  io.result := sum\n",
    "}\n",
    "\n",
    "showRtl(new ColorSumming(4, 8))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Counter with clear](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Examples/Simple%20ones/counter_with_clear.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Counter(width : Int) extends Component{\n",
    "  val io = new Bundle{\n",
    "    val clear = in Bool\n",
    "    val value = out UInt(width bits)\n",
    "  }\n",
    "  val register = Reg(UInt(width bits)) init(0)\n",
    "  register := register + 1\n",
    "  when(io.clear){\n",
    "    register := 0\n",
    "  }\n",
    "  io.value := register\n",
    "}\n",
    "\n",
    "showRtl(new Counter(4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [PLL BlackBox and reset controller](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Examples/Simple%20ones/pll_resetctrl.html)\n",
    "#### The PLL BlackBox definition"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PLL extends BlackBox{\n",
    "  val io = new Bundle{\n",
    "    val clkIn    = in Bool\n",
    "    val clkOut   = out Bool\n",
    "    val isLocked = out Bool\n",
    "  }\n",
    "\n",
    "  noIoPrefix()\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### TopLevel definition"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component{\n",
    "  val io = new Bundle {\n",
    "    val aReset    = in Bool\n",
    "    val clk100Mhz = in Bool\n",
    "    val result    = out UInt(4 bits)\n",
    "  }\n",
    "\n",
    "  // Create an Area to manage all clocks and reset things\n",
    "  val clkCtrl = new Area {\n",
    "    //Instanciate and drive the PLL\n",
    "    val pll = new PLL\n",
    "    pll.io.clkIn := io.clk100Mhz\n",
    "\n",
    "    //Create a new clock domain named 'core'\n",
    "    val coreClockDomain = ClockDomain.internal(\n",
    "      name = \"core\",\n",
    "      frequency = FixedFrequency(200 MHz)  // This frequency specification can be used\n",
    "    )                                      // by coreClockDomain users to do some calculations\n",
    "\n",
    "    //Drive clock and reset signals of the coreClockDomain previously created\n",
    "    coreClockDomain.clock := pll.io.clkOut\n",
    "    coreClockDomain.reset := ResetCtrl.asyncAssertSyncDeassert(\n",
    "      input = io.aReset || ! pll.io.isLocked,\n",
    "      clockDomain = coreClockDomain\n",
    "    )\n",
    "  }\n",
    "\n",
    "  //Create a ClockingArea which will be under the effect of the clkCtrl.coreClockDomain\n",
    "  val core = new ClockingArea(clkCtrl.coreClockDomain){\n",
    "    //Do your stuff which use coreClockDomain here\n",
    "    val counter = Reg(UInt(4 bits)) init(0)\n",
    "    counter := counter + 1\n",
    "    io.result := counter\n",
    "  }\n",
    "}\n",
    "\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [RGB to gray](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Examples/Simple%20ones/rgb_to_gray.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class RgbToGray extends Component{\n",
    "  val io = new Bundle{\n",
    "    val clear = in Bool\n",
    "    val r,g,b = in UInt(8 bits)\n",
    "\n",
    "    val wr = out Bool\n",
    "    val address = out UInt(16 bits)\n",
    "    val data = out UInt(8 bits)\n",
    "  }\n",
    "\n",
    "  def coef(value : UInt,by : Float) : UInt = (value * U((255*by).toInt,8 bits) >> 8)\n",
    "  val gray = RegNext(\n",
    "    coef(io.r,0.3f) +\n",
    "    coef(io.g,0.4f) +\n",
    "    coef(io.b,0.3f)\n",
    "  )\n",
    "\n",
    "  val address = CounterFreeRun(stateCount = 1 << 16)\n",
    "  io.address := address\n",
    "  io.wr := True\n",
    "  io.data := gray\n",
    "\n",
    "  when(io.clear){\n",
    "    gray := 0\n",
    "    address.clear()\n",
    "    io.wr := False\n",
    "  }\n",
    "}\n",
    "\n",
    "showRtl(new RgbToGray)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Sinus rom](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Examples/Simple%20ones/sinus_rom.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel(resolutionWidth: Int, sampleCount: Int) extends Component {\n",
    "  val io = new Bundle {\n",
    "    val sin = out SInt(resolutionWidth bits)\n",
    "    val sinFiltred = out SInt(resolutionWidth bits)\n",
    "  }\n",
    "\n",
    "  def sinTable = for(sampleIndex <- 0 until sampleCount) yield {\n",
    "    val sinValue = Math.sin(2 * Math.PI * sampleIndex / sampleCount)\n",
    "    S((sinValue * ((1<<resolutionWidth)/2-1)).toInt,resolutionWidth bits)\n",
    "  }\n",
    "\n",
    "  val rom =  Mem(SInt(resolutionWidth bits),initialContent = sinTable)\n",
    "  val phase = Reg(UInt(log2Up(sampleCount) bits)) init(0)\n",
    "  phase := phase + 1\n",
    "\n",
    "  io.sin := rom.readSync(phase)\n",
    "  io.sinFiltred := RegNext(io.sinFiltred  - (io.sinFiltred  >> 5) + (io.sin >> 5)) init(0)\n",
    "}\n",
    "\n",
    "showRtl(new TopLevel(32, 64))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Scala",
   "language": "scala",
   "name": "scala"
  },
  "language_info": {
   "codemirror_mode": "text/x-scala",
   "file_extension": ".scala",
   "mimetype": "text/x-scala",
   "name": "scala",
   "nbconvert_exporter": "script",
   "version": "2.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
